﻿using System;
using System.ComponentModel;
using System.Net;
using System.Text;

namespace Toybox.NicoSharp.Abstracts
{
	using Extensions;
	using Utilities;

	/// <summary>
	/// Key の Abstract クラス
	/// </summary>
	public abstract class AbstractKey : EventArgs, INotifyPropertyChanged
	{

		#region [INotifyPropertyChanged]

		/// <summary>
		/// Property 変化イベント
		/// </summary>
		public event PropertyChangedEventHandler PropertyChanged;

		/// <summary>
		/// Property 変化
		/// </summary>
		/// <param name="property"></param>
		protected void OnPropertyChanged(string property)
		{
			if (PropertyChanged != null)
				PropertyChanged(this, new PropertyChangedEventArgs(property));
		}

		#endregion [INotifyPropertyChanged]


		#region Constructor

		/// <summary>
		/// Constructor
		/// </summary>
		/// <param name="thread"></param>
		/// <param name="cookies"></param>
		public AbstractKey(string thread, CookieCollection cookies)
		{
			this.Thread = thread;
			this.Cookies = cookies;
		}

		#endregion Constructor


		#region Events

		/// <summary>
		/// Update 完了イベント
		/// </summary>
		public event EventHandler<AbstractKey> UpdateCompleted;

		/// <summary>
		/// Update 完了
		/// </summary>
		/// <param name="key"></param>
		protected virtual void OnUpdateCompleted(AbstractKey key)
		{
			if (this.UpdateCompleted != null)
				this.UpdateCompleted(this, key);
		}

		#endregion Events


		#region Public Members

		/// <summary>
		/// Thread
		/// </summary>
		public string Thread
		{
			get { return _thread; }
			protected set
			{
				if (_thread == value) return;

				_thread = value;

				OnPropertyChanged("Thread");
			}
		}
		private string _thread;

		/// <summary>
		/// Cookie
		/// </summary>
		public CookieCollection Cookies
		{
			get { return _cookies; }
			protected set
			{
				if (_cookies == value) return;

				_cookies = value;

				OnPropertyChanged("Cookies");
			}
		}
		private CookieCollection _cookies;

		/// <summary>
		/// 期限切れ
		/// </summary>
		public virtual bool Expired
		{
			get { return Expires < DateTime.UtcNow.GetUnixTime(); }
		}

		/// <summary>
		/// 期限
		/// </summary>
		public int Expires
		{
			get { return _expires; }
			protected set
			{
				if (_expires == value)
					return;

				_expires = value;

				OnPropertyChanged("Expires");
				OnPropertyChanged("Expired");
			}
		}
		private int _expires;

		/// <summary>
		/// Key
		/// </summary>
		public string Value
		{
			get { return _value; }
			protected set
			{
				if (_value == value) return;

				_value = value;

				OnPropertyChanged("Value");
			}
		}
		private string _value;

		#endregion Public Members


		#region Override Methods

		/// <summary>
		/// Update
		/// </summary>
		/// <param name="url"></param>
		/// <returns></returns>
		protected virtual string Update(string url)
		{
			SetKey(NicoWebClient.Get(url, this.Cookies));
			return this.Value;
		}

		/// <summary>
		/// Update (非同期)
		/// </summary>
		/// <param name="url"></param>
		protected virtual void UpdateAsync(string url)
		{
			var wc = new NicoWebClient();
			wc.DownloadStringCompleted += wc_DownloadStringCompleted;
			wc.Encoding = Encoding.UTF8;
			wc.CookieContainer.Add(this.Cookies);

			wc.DownloadStringAsync(new Uri(url));
		}

		/// <summary>
		/// Key をセット
		/// </summary>
		/// <param name="text"></param>
		protected abstract void SetKey(string text);

		#endregion Override Methods

		#region Private Methods

		/// <summary>
		/// Update (非同期)完了後発生
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		private void wc_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
		{
			NicoWebClient wc = sender as NicoWebClient;

			SetKey(e.Result);

			wc.Dispose();
			OnUpdateCompleted(this);
		}

		#endregion Private Methods

	}
}
